//---------------------------------------------------------------------------

#include <vcl.h>
#include <richedit.h>
#include <EIC.h>
#pragma hdrstop

#include "uEtat.h"
#include "uFncGDI.h"
#include "uRtf.h"
#include "ReOleCB.h"
#include "Printer.h"
#pragma package(smart_init)
#define MODULE_TAG MODULE_TAG_RTF

#define RICHEDIT_UNICODE

#ifndef RICHEDIT_UNICODE
    #define MY_RICHEDIT_CLASS  RICHEDIT_CLASS
    #define MY_RICHEDIT_DLL    "riched20.dll"
#else
    #define MY_RICHEDIT_CLASS  "RichEdit50W"
    #define MY_RICHEDIT_DLL    "MsftEdit.dll"
#endif

//#define FL_VISIBLE WS_VISIBLE
#define FL_VISIBLE 0
//---------------------------------------------------------------------------
#define FOND_RICHEDT RGB(255,0,255)//255,0,255)
typedef struct tagCOOKIE
{
   HANDLE hFile;
   LPBYTE pbStart;
   LPBYTE pbCur;
   LONG  bCount;
} COOKIE, * PCOOKIE;

DWORD CALLBACK EditStreamCallback (DWORD dwCookie, LPBYTE pbBuff, long cb, long FAR *pcb)
{
    PCOOKIE pCookie = (PCOOKIE)dwCookie;
    if( pCookie->hFile)
    {
        if( ::ReadFile( pCookie->hFile, pbBuff, (unsigned long)cb, (unsigned long*)pcb, NULL) == 0)
            return 1;
    }
    else
    {
        LONG   bytesLeft, bytesRead;
            // Calc the bytes read.
        bytesRead = pCookie->pbCur - pCookie->pbStart;
            // Calc bytes left to read.
        if (bytesRead < pCookie->bCount)
            // Calc the bytes left to read.
            bytesLeft = pCookie->bCount - bytesRead;
        else
            bytesLeft = 0;

            // Don’t read past the end of buffer.
        if (cb > bytesLeft) cb = bytesLeft;
            // Set bytes read.
        *pcb = cb;
            // Copy any bytes.
        if (cb)
        {
            memcpy(pbBuff, pCookie->pbCur, cb);
            pCookie->pbCur += cb;
        }
    }
    // Return no error.
    return 0;
}
//---------------------------------------------------------------------------

LRESULT CALLBACK SubClassPapaRichEdit (HWND hWnd,	// handle to window
                                   UINT Msg,	// message
                                   WPARAM WParam,	// first message parameter
                                   LPARAM LParam )	// second message parameter
{
    switch( Msg)
    {
        case WM_NOTIFY :
        {
            NMHDR *nmhdr = (NMHDR*)LParam;
            if( (nmhdr->code == EN_REQUESTRESIZE) && Glob->Rtf)
            {
                REQRESIZE *rq = (REQRESIZE*)LParam;
                Glob->Rtf->HauteurVoulueParRichEdit = TCoordonnee::Pixels2Twips( rq->rc.bottom - rq->rc.top, Glob->ResolEcran);
    //            ::MulDiv( rq->rc.bottom - rq->rc.top, _Resolution, Glob->ResolEcran) + 1;
            }
        }
    }
    return ::CallWindowProc( (FARPROC)Glob->Rtf->AncPapaWndProc, hWnd, Msg, WParam, LParam);
}
//---------------------------------------------------------------------------
__fastcall CRtf::CRtf( )
{
    m_hRichEditdll = 0;
    m_pRECallback = NULL;
    m_hRchEdt = 0;
    m_hPere = 0;
    m_Font = NULL;
    HauteurVoulueParRichEdit = -1;
    AncPapaWndProc = NULL;
    m_Presentation = (Text_Presentation)0;
}
//---------------------------------------------------------------------------
__fastcall CRtf::~CRtf( )
{
        if( IsWindow(m_hRchEdt))
            ::DestroyWindow( m_hRchEdt);
        if( IsWindow(m_hPere))
        {
            if( AncPapaWndProc)
                ::SetWindowLong( m_hPere, GWL_WNDPROC, (long)AncPapaWndProc);
            ::PostMessage( m_hPere, WM_CLOSE, 0,0);
            ::DestroyWindow( m_hPere);
        }
        if( m_pRECallback)       delete m_pRECallback;
        if( m_Font)              delete m_Font;
        if( m_hRichEditdll)    ::FreeLibrary( m_hRichEditdll);
}
//---------------------------------------------------------------------------
void __fastcall CRtf::Init()
{
    ChkSDK( TAGL, (m_hRichEditdll = ::LoadLibrary( MY_RICHEDIT_DLL)), NULL);

    InitDCEcran();
}
//---------------------------------------------------------------------------
void __fastcall CRtf::SupprimeCharacteres( int Begin, int End)
{
    if( (Begin != -1) && (End != -1))
    {
        CHARRANGE CharRange;
        CharRange.cpMin = Begin;
        CharRange.cpMax = End;
        ::SendMessage( m_hRchEdt, EM_EXSETSEL, 0, (long)&CharRange);
    }
    ::SendMessage( m_hRchEdt, EM_REPLACESEL, 0, (long)"\0\0");
}

void __fastcall CRtf::SuppressionLignesVideALaFin()
{
    int nNbLines = ::SendMessage( m_hRchEdt, EM_GETLINECOUNT, 0, 0)-1;
    bool bLigneVide = false;
#ifndef RICHEDIT_UNICODE
    AnsiString s;
#else
    WideString s;
#endif
    int TypeSel;
    do
    {
        CHARRANGE CharRange;
        CharRange.cpMin = max(0L,::SendMessage( m_hRchEdt, EM_LINEINDEX, nNbLines, 0)-1);
        CharRange.cpMax = -1;
        ::SendMessage( m_hRchEdt, EM_EXSETSEL, 0, (long)&CharRange);   //on sélectionne la dernière ligne
        TypeSel = ::SendMessage( m_hRchEdt, EM_SELECTIONTYPE, 0, (long)&CharRange);
        bLigneVide = (TypeSel == SEL_EMPTY);
        if( !bLigneVide && ((TypeSel & ~(SEL_TEXT | SEL_MULTICHAR)) == 0))
        {   // pas d'objets sur la ligne
          PARAFORMAT2 ParaFormat;
          memset( &ParaFormat, 0, sizeof( ParaFormat));
          ParaFormat.cbSize = sizeof( ParaFormat);
          ::SendMessage( m_hRchEdt, EM_GETPARAFORMAT, 0, (long)&ParaFormat);
          if( ParaFormat.wEffects & PFE_TABLE)
            bLigneVide = false;
          else
          { // cette ligne ne concerne pas un tableau
            ::SendMessage( m_hRchEdt, EM_EXGETSEL, 0, (long)&CharRange);
            int n = CharRange.cpMax - CharRange.cpMin;
              //on fixe la longueur du buffer à la taille de la selection
            s.SetLength( n +2);

#ifndef RICHEDIT_UNICODE
            memset( s.c_str(), 0, n + 2);
            ::SendMessage( m_hRchEdt, EM_GETSELTEXT, 0, (long)s.c_str());
#else
            memset( s.c_bstr(), 0, n + 2);
            ::SendMessage( m_hRchEdt, EM_GETSELTEXT, 0, (long)s.c_bstr());
#endif
            bLigneVide = true;
            for( int j = 1; bLigneVide && j <= n; j++)
            {
              switch( s[j])
              {
                case L'\0':
                case L' ':
                case L'\t':
                case L'\r':
                case L'\n': break;
                default : bLigneVide = false;
              }
            }
          }
        }

        if( bLigneVide)
            SupprimeCharacteres( -1,-1);
        nNbLines--;
    }while( bLigneVide && nNbLines >= 0);

}

void __fastcall CRtf::InitContenu( const TCoorRect &Rc, const EICFont *Font, const AnsiString& Texte, Text_Presentation Presentation, long FirstCharPrint)
{
    try{
        Init();
        int Largeur = TCoordonnee::Twips2Pixels(Rc.Width.Twips, Screen->PixelsPerInch);
        int Hauteur = TCoordonnee::Twips2Pixels(Rc.Height.Twips, Screen->PixelsPerInch);
        if( m_Presentation != Presentation)
        {
            if( !m_hPere)
            {   m_hPere = ::CreateWindow( "STATIC", "", WS_BORDER | FL_VISIBLE,
                                  0, 0, Largeur, 800,
                                  NULL, NULL, 0, NULL);
                AncPapaWndProc = (WNDPROC)::SetWindowLong( m_hPere, GWL_WNDPROC, (long)SubClassPapaRichEdit);
            }
            DWORD Style = ES_MULTILINE | WS_CLIPSIBLINGS | ES_WANTRETURN | FL_VISIBLE;
            if( m_hPere)                         Style |= WS_CHILD;
            if( Presentation & Tx_ALaLigne)      Style |= ES_AUTOVSCROLL;
            if( Presentation & Tx_HDroite)       Style |= ES_RIGHT;
            else if( Presentation & Tx_HCentre)  Style |= ES_CENTER;
            else                                 Style |= ES_LEFT;
            if( (Presentation != m_Presentation) && m_hRchEdt)
            {
                ::DestroyWindow( m_hRchEdt);
                m_hRchEdt = 0;
            }

            if( m_hRchEdt)
            {
                ::SetWindowLong( m_hRchEdt, GWL_STYLE, Style);
                SupprimeCharacteres( 0, -1);

            }
            else
            {
                ChkSDK( TAGL, (m_hRchEdt = ::CreateWindowEx( WS_EX_TRANSPARENT, MY_RICHEDIT_CLASS, "",
                                                             Style,
                                                             0, 0, Largeur, Hauteur,
                                                             m_hPere, NULL, 0, NULL)), 0);
                ASSERT(m_hRchEdt);

                //Activation de la typographie avancée.
                // => Permet d'afficher correctement les textes justifiés et autres évolutions
                ::SendMessage(m_hRchEdt, EM_SETTYPOGRAPHYOPTIONS, TO_ADVANCEDTYPOGRAPHY, 1);

                   // Paramètres OLE
                if( m_pRECallback)
                {
    //                m_pRECallback->Release();
                    delete m_pRECallback; m_pRECallback = NULL;
                }
                m_pRECallback = new CRichEditOleCallback( m_hRchEdt);
                m_pRECallback->AddRef();
                ::SendMessage( m_hRchEdt, EM_SETOLECALLBACK, 0, (long)m_pRECallback);
                LPRICHEDITOLE pRichEditOle = NULL;
                ::SendMessage(m_hRchEdt, EM_GETOLEINTERFACE, 0, (LPARAM) (LPVOID*) &pRichEditOle);

                //
                // Some applications fail to insert if the hostname is not set (for
                // example, MS Word) so this is essential to be done.
                //
                if (pRichEditOle)
                    pRichEditOle->SetHostNames("GenEtat", TEXT("Untitled"));

                m_Rc           = Rc;
                m_Presentation = Presentation;
            }
        }
        if( m_Rc != Rc)
        {
            RECT r;
            ::GetWindowRect( m_hPere, &r);
            ::MoveWindow( m_hPere, 0, 0, Largeur, r.bottom - r.top, true);
            ::MoveWindow( m_hRchEdt, 0, 0, Largeur, Hauteur, true);
            m_Rc = Rc;
        }
    #if FL_VISIBLE
        SetWindowText( m_hPere, (AnsiString( "Taille : ") + Largeur + "x" + Hauteur).c_str());
    #endif
        if( Font && m_Font != Font)
        {
            LOGFONT lgf;
            ::_GetObject( TAGL, Font->Handle, sizeof( lgf), &lgf);
            ::CHARFORMAT2 charformat;
            memset( &charformat, 0, sizeof( charformat));
            charformat.cbSize           = sizeof( charformat);
            charformat.dwMask           = CFM_SIZE | CFM_ITALIC | CFM_UNDERLINE | CFM_STRIKEOUT |
                                          CFM_COLOR | CFM_CHARSET | CFM_FACE | CFM_WEIGHT | CFM_BACKCOLOR;// | CFM_SPACING ;
            charformat.yHeight          = Font->Size * 20;// * Glob->ResolEcran / Screen->PixelsPerInch;
            charformat.crTextColor      = ColorToRGB( Font->Color);
            charformat.crBackColor      = ColorToRGB( clWindow);
            charformat.bCharSet         = lgf.lfCharSet;
            charformat.bPitchAndFamily  = lgf.lfPitchAndFamily;
            strcpy( charformat.szFaceName, Font->Name.c_str());
            charformat.wWeight          = (WORD)lgf.lfWeight;
            charformat.dwEffects        = (lgf.lfItalic?CFE_ITALIC:0)
                                        | (lgf.lfUnderline?CFE_UNDERLINE:0)
                                        | (lgf.lfStrikeOut ?CFE_STRIKEOUT:0);
//            charformat.bUnderlineType   =
//            charformat.sSpacing   = -50;

//            ::SendMessage( m_hRchEdt, EM_GETCHARFORMAT , SCF_DEFAULT, (long)&charformat);
            ::SendMessage( m_hRchEdt, EM_SETCHARFORMAT , SCF_ALL, (long)&charformat);
            delete m_Font;
            m_Font = new EICFont( );
            *m_Font = *Font;
        }
        if( Presentation & Tx_HJustify)
        {
            PARAFORMAT2 pf;
            memset( &pf, 0, sizeof( pf));
            pf.cbSize = sizeof( pf);
            pf.dwMask = PFM_ALIGNMENT;
            pf.wAlignment = PFA_JUSTIFY;
            ChkSDK(TAGL, ::SendMessage (m_hRchEdt, EM_SETPARAFORMAT, 0, (LPARAM)&pf), 0);
        }

//        if( (m_Texte != Texte) || (m_FirstCharPrint != FirstCharPrint ))
        {
            // Le premier paramètre du EXLIMITTEXT est documenté et il est indiqué que quand il est fixé à 0
            // La taille max de texte est 65536. Le deuxième paramètre est indiqué non utilisé ou réservé mais
            // utilisé dans les sources des bpl ; Fixé à 7FFFFFF0, il permet de charger un richedit avec autant
            // de caractères que l'on souhaite
            ::SendMessage (m_hRchEdt, EM_EXLIMITTEXT, 0,0x7FFFFFF0);
            WPARAM iAttrib;

            COOKIE cookie;
            memset( &cookie, 0, sizeof( cookie));

            EDITSTREAM eStream;
            eStream.dwCookie = (DWORD)&cookie;
            eStream.pfnCallback = EditStreamCallback;
            eStream.dwError = 0;

            if( !Texte.Pos( DebutTexteRTF) && ::FileExists( Texte))
            {
                OFSTRUCT of;
                memset( &of, 0, sizeof( of));
                cookie.hFile = (HANDLE)::OpenFile (Texte.c_str(), &of, OF_READ);

                if( cookie.hFile)
                {
                    char pbBuff[10];
                    unsigned long ul;
                    ::ReadFile( cookie.hFile, pbBuff, sizeof(pbBuff), &ul, NULL);
                    pbBuff[9]='\0';
                    iAttrib = (strstr( pbBuff, DebutTexteRTF)==pbBuff)? SF_RTF: SF_TEXT;
                    ::SetFilePointer( cookie.hFile, 0, NULL, FILE_BEGIN);
                    ::SendMessage (m_hRchEdt, EM_STREAMIN, iAttrib, (LPARAM)&eStream);
                    if( eStream.dwError != 0)
                    {
                      SetLastError( eStream.dwError);
                      TraiteLastError( TAGL, "EM_STREAMIN");
                    }
                    ::CloseHandle ((HANDLE)cookie.hFile);
                }
            }else
            {
                AnsiString s = Texte;
                iAttrib = ( Texte.Pos(DebutTexteRTF) == 1)? SF_RTF : SF_TEXT;
                if( iAttrib == SF_TEXT)
                    s = FormateTexte( Presentation, s, tf_Normal, NULL);
                cookie.pbStart  = (LPBYTE)s.c_str();      // Pointer to memory block
                cookie.pbCur    = cookie.pbStart;
                cookie.bCount   = s.Length();         // Size of ink data

                ::SendMessage (m_hRchEdt, EM_STREAMIN, iAttrib, (LPARAM)&eStream);
            }
            if( FirstCharPrint != -1L)
                SupprimeCharacteres( 0, FirstCharPrint);

            /* Suppression des lignes vides à la fin */
            if( !(Presentation & Tx_DontTrim))
                SuppressionLignesVideALaFin();

            m_Texte            = Texte;
            m_FirstCharPrint   = FirstCharPrint;
        }
        SendMessage( m_hRchEdt, EM_SETTARGETDEVICE, (WPARAM)Glob->hDCEcran, TCoordonnee::Pixels2Twips( Largeur, Screen->PixelsPerInch));
    }CATCH_EXCEPTION( TAG( 1))
}
//---------------------------------------------------------------------------

TCoordonnee __fastcall CRtf::GetHauteur( )
{
    int Mask;
    ASSERT( m_hRchEdt);
    Mask = ::SendMessage(m_hRchEdt, EM_GETEVENTMASK, 0, 0);
    Mask = (Mask | ENM_REQUESTRESIZE);
    ::SendMessage(m_hRchEdt, EM_SETEVENTMASK, 0, Mask);
    ::SendMessage(m_hRchEdt, EM_REQUESTRESIZE, 0, 0);  //permet d'initialiser _HauteurVoulueParRichEdit

    return HauteurVoulueParRichEdit;
}
//---------------------------------------------------------------------------
void __fastcall CRtf::Draw( TObject *Support, const TCoorRect &_Rc, long &nCharFin)
{
  try{
    TCoorRect       Rc = _Rc;
    LOGFONT         lf;
    FORMATRANGE     FormatRange;
    long            lTextLength;
    int             nCharExtra;
    COLORREF        TextColor;
    GETTEXTLENGTHEX gtlex = { GTL_PRECISE, CP_ACP };
    TCanvas *canvas = (TCanvas*)Support;
    bool            bNoEMF = ( IsPrinting() && IsValidCanvas( Support)
                             && (_WINPLATFORM == VP_WINDOWS_95_98) && Glob->EICPrinter->PDF );
    HDC hMetaDC;
    if( bNoEMF && IsValidCanvas( Support))
        hMetaDC = canvas->Handle;
    else
        hMetaDC = ::_MyCreateEnhMetaFile( TAGL, Rc.Width, Rc.Height, Screen->PixelsPerInch/*, AnsiString("c:\\temp\\test\\") + Rc.Top.PixelsY + " " +Rc.Height.PixelsY+".emf"*/);

    ::SendMessage(m_hRchEdt, EM_FORMATRANGE, 0, 0);
    lTextLength = ::SendMessage( m_hRchEdt, EM_GETTEXTLENGTHEX, (WPARAM)&gtlex, 0 );
    ::SendMessage( m_hRchEdt, EM_SETSEL, 0, -1);

    ::ZeroMemory(&FormatRange, sizeof(FormatRange));
    if( IsPrinting())
    {
        TRect Rc1;      Rc1.Left = 0; Rc1.Top = 0; Rc1.Right = 0; Rc1.Bottom = 0;
        double h = Rc.Height.Twips, l= Rc.Width.Twips;
        Glob->EICPrinter->RectifieCoordonnees(Rc1);
        Rc.Left.Twips = Rc.Left.Twips + TCoordonnee::Pixels2Twips( Rc1.Left, Glob->ResolutionX);
        Rc.Top.Twips = Rc.Top.Twips + TCoordonnee::Pixels2Twips( Rc1.Top, Glob->ResolutionY);
        Rc.Right.Twips = Rc.Left.Twips + l;
        Rc.Bottom.Twips = Rc.Top.Twips + h;
    }

    FormatRange.hdcTarget = Glob->hDCEcran;
    FormatRange.rc.left   = floor(bNoEMF? Rc.Left.Twips       : 0);
    FormatRange.rc.top    = floor(bNoEMF? Rc.Top.Twips        : 0);
    FormatRange.rc.right  = ceil( bNoEMF? Rc.Right.Twips      : Rc.Width.Twips);
    FormatRange.rc.bottom = ceil( bNoEMF? Rc.Bottom.Twips     : Rc.Height.Twips);
    FormatRange.rcPage.left   = floor(bNoEMF? Rc.Left.Twips   : 0);
    FormatRange.rcPage.top    = floor(bNoEMF? Rc.Top.Twips    : 0);
    FormatRange.rcPage.right  = ceil( bNoEMF? Rc.Right.Twips  : Rc.Width.Twips);
    FormatRange.rcPage.bottom = ceil( bNoEMF? Rc.Bottom.Twips : Rc.Height.Twips);
//    FormatRange.rcPage    = FormatRange.rc;
    FormatRange.hdc       = hMetaDC;
  // Default the range of text to print as the entire document.
    FormatRange.chrg.cpMin = 0;
    FormatRange.chrg.cpMax = nCharFin;
    POINTL pt;
    do{
      nCharFin = ::SendMessage( m_hRchEdt, EM_FORMATRANGE, false, (long)&FormatRange)-1;

      if( nCharFin && (FormatRange.rc.bottom > FormatRange.rcPage.bottom))
      {
        if( nCharFin == -1)
          nCharFin = ::SendMessage( m_hRchEdt, EM_LINEINDEX, ::SendMessage( m_hRchEdt, EM_GETLINECOUNT, 0, 0), 0);
        else{
          int nLine = ::SendMessage( m_hRchEdt, EM_LINEFROMCHAR,nCharFin, 0);
          if( nLine)
            nCharFin = ::SendMessage( m_hRchEdt, EM_LINEINDEX, nLine-1, 0);
          else{
            nCharFin = 0;
            FormatRange.chrg.cpMax = nCharFin;
            break;
          }
        }
        FormatRange.chrg.cpMax = nCharFin;
        ::SendMessage( m_hRchEdt, EM_FORMATRANGE, 0, NULL);
        continue;
      }
      break;
    }while( true);

    if( (FormatRange.chrg.cpMax == -1) || (FormatRange.chrg.cpMin < FormatRange.chrg.cpMax))
      ::SendMessage( m_hRchEdt, EM_DISPLAYBAND, 0, (long)&FormatRange.rc);
    if( !bNoEMF)
    {
        HENHMETAFILE hemf = ::_CloseEnhMetaFile( TAGL, hMetaDC );
        RECT r = Rc.RECTPixels;     r.bottom++;// permet de toujours imprimer les lignes de fin de tableau
        if( IsValidCanvas( Support))
            ::_PlayEnhMetaFile( TAGL, canvas->Handle, hemf, &r);
        ::_DeleteEnhMetaFile(TAGL, hemf);
    }

    if( nCharFin >= lTextLength)  //attention il va rester la dernière ligne si elle est vide
        nCharFin = -1;
    ::SendMessage( m_hRchEdt, EM_FORMATRANGE, 0, NULL);

/*    if( Bmp)
    {
        if( IsValidCanvas( Support))
        {
            MyStretchDraw( (TCanvas*)Support, _Rc.RectPixels, Bmp);
        }
        delete Bmp;
    }else{
        ::_SetTextCharacterExtra( TAGL, canvas->Handle, nCharExtra);
        ::_SetTextColor( TAGL, canvas->Handle, TextColor);
    }
    if( hdc) ::_DeleteDC( TAGL, hdc);*/
    }CATCH_EXCEPTION( TAG(2))
}


#define ReleaseOLE( Obj)  if( Obj) { Obj->Release(); Obj = NULL;}

short COle::nbInstances = 0;
DVTARGETDEVICE *COle::ms_ptd = NULL;

#if 0
struct IID_ENTRY
	{
		const IID* piid;
		LPCTSTR lpszName;
	};

#define MAKE_IID_ENTRY(name) { &name, _T(#name) }

	static const IID_ENTRY iidNameTable[] =
	{
		MAKE_IID_ENTRY(IID_IAdviseSink),
		MAKE_IID_ENTRY(IID_IAdviseSink2),
		MAKE_IID_ENTRY(IID_IBindCtx),
		MAKE_IID_ENTRY(IID_IClassFactory),
		MAKE_IID_ENTRY(IID_IContinueCallback),
		MAKE_IID_ENTRY(IID_IEnumOleDocumentViews),
		MAKE_IID_ENTRY(IID_IOleCommandTarget),
		MAKE_IID_ENTRY(IID_IOleDocument),
		MAKE_IID_ENTRY(IID_IOleDocumentSite),
		MAKE_IID_ENTRY(IID_IOleDocumentView),
		MAKE_IID_ENTRY(IID_IPrint),
		MAKE_IID_ENTRY(IID_IDataAdviseHolder),
		MAKE_IID_ENTRY(IID_IDataObject),
		MAKE_IID_ENTRY(IID_IDebug),
		MAKE_IID_ENTRY(IID_IDebugStream),
		MAKE_IID_ENTRY(IID_IDfReserved1),
		MAKE_IID_ENTRY(IID_IDfReserved2),
		MAKE_IID_ENTRY(IID_IDfReserved3),
		MAKE_IID_ENTRY(IID_IDispatch),
		MAKE_IID_ENTRY(IID_IDropSource),
		MAKE_IID_ENTRY(IID_IDropTarget),
		MAKE_IID_ENTRY(IID_IEnumCallback),
		MAKE_IID_ENTRY(IID_IEnumFORMATETC),
		MAKE_IID_ENTRY(IID_IEnumGeneric),
		MAKE_IID_ENTRY(IID_IEnumHolder),
		MAKE_IID_ENTRY(IID_IEnumMoniker),
		MAKE_IID_ENTRY(IID_IEnumOLEVERB),
		MAKE_IID_ENTRY(IID_IEnumSTATDATA),
		MAKE_IID_ENTRY(IID_IEnumSTATSTG),
		MAKE_IID_ENTRY(IID_IEnumString),
		MAKE_IID_ENTRY(IID_IEnumUnknown),
		MAKE_IID_ENTRY(IID_IEnumVARIANT),
//      MAKE_IID_ENTRY(IID_IExternalConnection),
		MAKE_IID_ENTRY(IID_IInternalMoniker),
		MAKE_IID_ENTRY(IID_ILockBytes),
		MAKE_IID_ENTRY(IID_IMalloc),
		MAKE_IID_ENTRY(IID_IMarshal),
		MAKE_IID_ENTRY(IID_IMessageFilter),
		MAKE_IID_ENTRY(IID_IMoniker),
		MAKE_IID_ENTRY(IID_IOleAdviseHolder),
		MAKE_IID_ENTRY(IID_IOleCache),
		MAKE_IID_ENTRY(IID_IOleCache2),
		MAKE_IID_ENTRY(IID_IOleCacheControl),
		MAKE_IID_ENTRY(IID_IOleClientSite),
		MAKE_IID_ENTRY(IID_IOleContainer),
		MAKE_IID_ENTRY(IID_IOleInPlaceActiveObject),
		MAKE_IID_ENTRY(IID_IOleInPlaceFrame),
		MAKE_IID_ENTRY(IID_IOleInPlaceObject),
		MAKE_IID_ENTRY(IID_IOleInPlaceSite),
		MAKE_IID_ENTRY(IID_IOleInPlaceUIWindow),
		MAKE_IID_ENTRY(IID_IOleItemContainer),
		MAKE_IID_ENTRY(IID_IOleLink),
		MAKE_IID_ENTRY(IID_IOleManager),
		MAKE_IID_ENTRY(IID_IOleObject),
		MAKE_IID_ENTRY(IID_IOlePresObj),
		MAKE_IID_ENTRY(IID_IOleWindow),
		MAKE_IID_ENTRY(IID_IPSFactory),
		MAKE_IID_ENTRY(IID_IParseDisplayName),
		MAKE_IID_ENTRY(IID_IPersist),
		MAKE_IID_ENTRY(IID_IPersistFile),
		MAKE_IID_ENTRY(IID_IPersistStorage),
		MAKE_IID_ENTRY(IID_IPersistStream),
		MAKE_IID_ENTRY(IID_IProxyManager),
		MAKE_IID_ENTRY(IID_IRootStorage),
		MAKE_IID_ENTRY(IID_IRpcChannel),
		MAKE_IID_ENTRY(IID_IRpcProxy),
		MAKE_IID_ENTRY(IID_IRpcStub),
		MAKE_IID_ENTRY(IID_IRunnableObject),
		MAKE_IID_ENTRY(IID_IRunningObjectTable),
		MAKE_IID_ENTRY(IID_IStdMarshalInfo),
		MAKE_IID_ENTRY(IID_IStorage),
		MAKE_IID_ENTRY(IID_IStream),
		MAKE_IID_ENTRY(IID_IStubManager),
		MAKE_IID_ENTRY(IID_IUnknown),
		MAKE_IID_ENTRY(IID_IViewObject),
		MAKE_IID_ENTRY(IID_IViewObject2),
		MAKE_IID_ENTRY(IID_NULL),
	};
void  InsereInterfaces( TTreeNodes *ns, TTreeNode *n, IUnknown  *Ud)
{
TTreeNode *n1;
    IUnknown  *U=NULL;
    for( int i = 0; i < sizeof(iidNameTable)/sizeof(iidNameTable[0]); i++)
    {
        if( Ud->QueryInterface( *iidNameTable[i].piid, (void**)&U) ==0)
        {
            n1 = ns->AddChild( n,iidNameTable[i].lpszName);
            if( n1->Level < 1)
                InsereInterfaces( ns, n1, U);
        }
    }
}
#else
void  InsereInterfaces( TTreeNodes *ns, TTreeNode *n, IUnknown  *Ud)
{
}
#endif
DWORD WINAPI KillWindow(void*)
{
  fenetresuivante:
    HWND theHWND = NULL;
    HWND HWNDChild = NULL;

    while(!HWNDChild)
      {
      Sleep(10);
      theHWND = FindWindow("#32770", "Microsoft Excel");

      if (theHWND)  HWNDChild = FindWindowEx(theHWND, HWNDChild, "Button", "&Non");

      if(!HWNDChild) HWNDChild = FindWindowEx(theHWND, HWNDChild, "Button", "&Ne pas mettre à jour");
      }
    PostMessage(HWNDChild, WM_LBUTTONDOWN, MK_LBUTTON , 0);
    PostMessage(HWNDChild, WM_LBUTTONUP, MK_LBUTTON , 0);
    goto fenetresuivante;
}
//---------------------------------------------------------------------------

__fastcall COle::COle( const COle *Ole)
{
    m_pStg        = Ole->m_pStg;                     if( m_pStg)             m_pStg->AddRef();
	m_pOleObject  = Ole->m_pOleObject;               if( m_pOleObject)       m_pOleObject->AddRef();
    m_pViewObj    = Ole->m_pViewObj;                 if( m_pViewObj)         m_pViewObj->AddRef();
    m_pViewObj2   = Ole->m_pViewObj2;                if( m_pViewObj2)        m_pViewObj2->AddRef();
    m_pDataObj    = Ole->m_pDataObj;                 if( m_pDataObj)         m_pDataObj->AddRef();
    m_pRunObj     = Ole->m_pRunObj;                  if( m_pRunObj)          m_pRunObj->AddRef();
    m_Medium      = Ole->m_Medium;                   memset( (STGMEDIUM*)&Ole->m_Medium, 0, sizeof( Ole->m_Medium));
    m_Size        = Ole->m_Size;
    m_FormatEtc   = Ole->m_FormatEtc;           
    m_File        = Ole->m_File;
    m_bInitialise = Ole->m_bInitialise;
    m_bResize     = Ole->m_bResize;
    aFichierGenere= Ole->aFichierGenere;
    nbInstances++;
}

__fastcall COle::COle( const AnsiString &OLEFile)
{
    STATSTG Fichier;
    LPOLESTR Buffer = NULL;
    m_pStg       = NULL;
	  m_pOleObject = NULL;
    m_pViewObj   = NULL;
    m_pViewObj2  = NULL;
    m_pDataObj   = NULL;
    m_pRunObj    = NULL;
    m_Size.x = 0;
    m_Size.y = 0;
    HWND HWNDThread    = NULL;
    unsigned long lThreadID=0;
    SIZE Size = {0,0};
    m_bInitialise = false;
    try{try{
        if( !FileExists(OLEFile))  {EICErreur( AnsiString("Le fichier ") + OLEFile + " est inexistant. Veuillez modifier le fichier à inclure."); return;}
        m_File = OLEFile;

        CBarre Barre;
        Barre.Titre = "Ouverture du document externe " + OLEFile;
        Barre.Open();
        OLEInitialize();

        HWNDThread = ::CreateThread(NULL, 0, KillWindow, NULL, 0, &lThreadID);

        ChkOLE( TAGL, StgCreateDocfile( NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE
                                              | STGM_DIRECT | STGM_CREATE, 0, &m_pStg));
        nbInstances++;

        // récupération du nom du fichier généré pour pouvoir le supprimer après;
        m_pStg->Stat(&Fichier, STATFLAG_DEFAULT);
        aFichierGenere = AnsiString(WideString(Fichier.pwcsName));

        Buffer = new OLECHAR[m_File.Length()+1]; memset( Buffer, 0, (m_File.Length()+1)*sizeof( Buffer[0]));
        m_pOleObject = NULL;

        // On va essayer plusieurs méthode
        m_bInitialise = false;
        for( int Methode = 0; !m_bInitialise && Methode <= OLE_Max; Methode++)
        {
            memset( &m_Medium, 0, sizeof( m_Medium));
            memset( &m_FormatEtc, 0, sizeof( m_FormatEtc));
            m_FormatEtc.ptd      = ms_ptd;
            m_FormatEtc.dwAspect = DVASPECT_CONTENT;
            m_FormatEtc.lindex   = -1;
            m_FormatEtc.tymed    = TYMED_NULL;
            DWORD renderopt;

            // Ouverture du fichier
            switch( Glob->OLETabMethode[Methode])
            {
                case OLE_IViewObject2 :
                case OLE_IViewObject :
                        renderopt = OLERENDER_DRAW;
                    break;
                case OLE_IDataObject_EMF :
                        m_FormatEtc.cfFormat = CF_ENHMETAFILE;
                        m_FormatEtc.tymed    = TYMED_ENHMF;
                        renderopt = OLERENDER_FORMAT;
                    break;
                case OLE_IDataObject_WMF :
                        m_FormatEtc.cfFormat = CF_METAFILEPICT;
                        m_FormatEtc.tymed    = TYMED_MFPICT;
                        renderopt = OLERENDER_FORMAT;
                    break;
                case OLE_IDataObject_GDI :
                        m_FormatEtc.cfFormat = CF_BITMAP;
                        m_FormatEtc.tymed    = TYMED_GDI;
                        renderopt = OLERENDER_FORMAT;
                    break;
            }

            ::OleCreateFromFile( CLSID_NULL, m_File.WideChar(Buffer, m_File.Length()), IID_IOleObject,
                                 renderopt, (renderopt == OLERENDER_FORMAT)?&m_FormatEtc:NULL, NULL, m_pStg, (void **)&m_pOleObject);
            if( m_pOleObject)
            {
                switch( Glob->OLETabMethode[Methode])
                {
                    case OLE_IViewObject2 :
                        m_pOleObject->QueryInterface(IID_IViewObject2, (void**)&m_pViewObj2);
                        if( m_pViewObj2)
                        {
                            ChkOLE( TAGL, m_pViewObj2->GetExtent( m_FormatEtc.dwAspect, m_FormatEtc.lindex, m_FormatEtc.ptd, &Size));
                            m_bInitialise = true;
                        }
                        break;
                    case OLE_IViewObject :
                        m_pOleObject->QueryInterface(IID_IViewObject, (void**)&m_pViewObj);
                        if( m_pViewObj)
                        {
                            ChkOLE( TAGL, m_pOleObject->GetExtent( m_FormatEtc.dwAspect, &Size));
                            m_bInitialise = true;
                        }
                        break;
                    case OLE_IDataObject_EMF :
                    case OLE_IDataObject_WMF :
                    case OLE_IDataObject_GDI :
                        m_pOleObject->QueryInterface(IID_IDataObject, (void**)&m_pDataObj);
                        if( m_pDataObj)
                        {
                            m_pOleObject->QueryInterface(IID_IRunnableObject, (void**)&m_pRunObj);
                            if( m_pRunObj)
                            {
                                int i;
                                ChkOLE( TAGL, m_pRunObj->Run( NULL));
                                HRESULT h = m_pDataObj->QueryGetData( &m_FormatEtc);
                                switch( h)
                                {
                                    case S_OK :
                                        {
                                            ChkOLE( TAGL, m_pDataObj->GetData( &m_FormatEtc, &m_Medium));
                                            m_bInitialise = true;
                                        }break;
                                    default : ChkOLE( TAGL, h); if( i) throw ELastError( TAGL, "QueryGetData");
                                    case -1 : ;
                                }
                                ReleaseOLE( m_pRunObj);
                            }
                            ReleaseOLE( m_pDataObj);
                        }
                        break;
                }
                if( m_bInitialise)
                {
                    switch( m_Medium.tymed)
                    {
                        case TYMED_MFPICT :
                            {   // conversion du METAFILE ancienne version en ENHMETAFILE
                                LPMETAFILEPICT pMP = (LPMETAFILEPICT )::_GlobalLock(TAGL, m_Medium.hMetaFilePict);
                                UINT nSize;     // size of metafile
                                LPBYTE lpvData;  // metafile data
                                nSize = ::_GetMetaFileBitsEx( TAGL, pMP->hMF, 0, NULL);
                                lpvData = (LPBYTE)::_GlobalAlloc( TAGL, GPTR, nSize);
                                ::_GetMetaFileBitsEx( TAGL, pMP->hMF, nSize, lpvData);
                                HENHMETAFILE hEMF = ::_SetWinMetaFileBits( TAGL, nSize, lpvData, Glob->hDCEcran, pMP);
                                ::_GlobalFree( TAGL, lpvData);
                                ::_GlobalUnlock(TAGL, m_Medium.hMetaFilePict);
                                ::_DeleteMetaFile(TAGL, m_Medium.hMetaFilePict);
                                m_Medium.tymed = TYMED_ENHMF;
                                m_Medium.hEnhMetaFile = hEMF;
                            }
                        case TYMED_ENHMF :
                            {
                                ENHMETAHEADER HeaderEnh;
                                ::_GetEnhMetaFileHeader( TAGL, m_Medium.hEnhMetaFile, sizeof( HeaderEnh), &HeaderEnh);
                                m_Size.x.Mm = double(HeaderEnh.rclFrame.right - HeaderEnh.rclFrame.left)/100.;
                                m_Size.y.Mm = double(HeaderEnh.rclFrame.bottom - HeaderEnh.rclFrame.top)/100.;
                            }break;
                        case TYMED_GDI :
                                ChkOLE( TAGL, m_pOleObject->GetExtent( m_FormatEtc.dwAspect, &Size));
                            break;
                    }
                }
            }
        }


        if( !m_bInitialise)//!m_pDataObj)
        {
            AnsiString sAppName = GetAppName();
            if( sAppName.IsEmpty())
                EICErreur( AnsiString("Le fichier ") + m_File +
                           " n'est pas lié avec une application OLE. Vous ne pouvez pas inclure ce fichier."
                           " Veuillez modifier le fichier à inclure.");
            else
                EICErreur( AnsiString("L'application \"") + sAppName + "\" utilisée pour lire le fichier \"" +
                           m_File + "\" ne supporte pas l'interface nécessaire pour dessiner."
                           " Ce fichier sera donc ignoré.");
        }else if( Size.cx && Size.cy)
        {
            m_Size.x.PixelsX = Size.cx / MM_PER_INCH;
            m_Size.y.PixelsY = Size.cy / MM_PER_INCH;
            m_Size.y.Twips++;
        }

    }CATCH_EXCEPTION( TAGL)
    }__finally{
        if( Buffer)     delete[] Buffer;
        if( HWNDThread) ::TerminateThread( (void*)HWNDThread, 0);
    }
}
__fastcall COle::~COle( )
{
    ReleaseOLE( m_pViewObj2);
    ReleaseOLE( m_pViewObj);
    ReleaseOLE( m_pDataObj);
    ReleaseOLE( m_pRunObj);
    switch( m_Medium.tymed)
    {
        case TYMED_ENHMF  : ::_DeleteEnhMetaFile(TAGL, m_Medium.hMetaFilePict); break;
        case TYMED_MFPICT : ::_DeleteMetaFile(TAGL, m_Medium.hMetaFilePict); break;
        case TYMED_GDI    : ::_DeleteObject (TAGL, m_Medium.hBitmap); break;
    }
    ReleaseOLE( m_pOleObject);
    ReleaseOLE( m_pStg);
    nbInstances--;
    if( !nbInstances && ms_ptd)
    {
        CoTaskMemFree( ms_ptd);
        ms_ptd = NULL;
    }
        //suppression du fichier temporaire
    if (FileExists(aFichierGenere)) DeleteFile(aFichierGenere);

    OLEUnInitialize();
}


void __fastcall COle::Draw( TObject *Support, const TCoorRect &_Rc, const TCoordonnee &LargeurEtat, bool bOnEstEnHautDeLaPage, long &NumPage)
{
//    short nbFeuillesEnHauteur = ceil( m_Size.y.Twips / Rc.Height.Twips);
//    short nbFeuillesEnLargeur = ceil( m_Size.x.Twips / LargeurEtat.Twips);
    NumPage++;
TRACEF(  TAGL, "COle::Draw bOnEstEnHautDeLaPage[%d] m_Size.y[%.2lf] Rc.Bottom-Rc.Top[%.2lf]", bOnEstEnHautDeLaPage, m_Size.y, (_Rc.Bottom-_Rc.Top));
    if( !bOnEstEnHautDeLaPage && ((m_Size.y-1) > (_Rc.Bottom-_Rc.Top)) && (NumPage == 0))
        return;

    if( IsValidCanvas( Support))
    {
        try{
            DVASPECTINFO dvFlag = {sizeof( dvFlag), DVASPECTINFOFLAG_CANOPTIMIZE};
            TCanvas *canvas = (TCanvas*)Support;

            TCoorRect Rc;
            Rc.Top.PixelsEcran  = _Rc.Top.PixelsEcran;
            Rc.Bottom.PixelsEcran = min( Rc.Top.PixelsEcran + m_Size.y.PixelsEcran, _Rc.Bottom.PixelsEcran);

            if( m_Size.x.PixelsEcran < (_Rc.Right.PixelsEcran - _Rc.Left.PixelsEcran))
            {
                Rc.Left.PixelsEcran  = _Rc.Left.PixelsEcran + (_Rc.Right.PixelsEcran - _Rc.Left.PixelsEcran - m_Size.x.PixelsEcran) / 2;
                Rc.Right.PixelsEcran = Rc.Left.PixelsEcran + m_Size.x.PixelsEcran;
            }else{
                Rc.Left.PixelsEcran  = _Rc.Left.PixelsEcran;
                Rc.Right.PixelsEcran  = _Rc.Right.PixelsEcran;
                if(!m_bResize)
                  {
                  Rc.Right.PixelsEcran = Rc.Left.PixelsEcran + m_Size.x.PixelsEcran;
                  Rc.Bottom.PixelsEcran = Rc.Top.PixelsEcran + m_Size.y.PixelsEcran;
                  }
            }
TRACEF(  TAGL, "COle::Draw [%d]  [%.2lf,%.2lf,%.2lf,%.2lf]  Rc.Bottom-Rc.Top[%.2lf]", Rc.Left, Rc.Top, Rc.Right, Rc.Bottom, (Rc.Bottom-Rc.Top));

            RECT rcBound = Rc.RECTPixels;
            if( IsPrinting()) Glob->EICPrinter->RectifieCoordonnees(rcBound);
            _RECTL rcBound1 = *(_RECTL*)&rcBound;

            ::_SetRectRgn( TAGL, Glob->hRgnTmp1, rcBound1.left, rcBound1.top, min(int(rcBound1.right+1),_Rc.Right.PixelsX), min(int(rcBound1.bottom+1),_Rc.Bottom.PixelsY) );
            ::_SelectClipRgn( TAGL, canvas->Handle, Glob->hRgnTmp1);

            switch( m_Medium.tymed)
            {
                case TYMED_ENHMF : ::_PlayEnhMetaFile( TAGL, canvas->Handle, m_Medium.hEnhMetaFile, (RECT*)&rcBound1); break;
                case TYMED_MFPICT: ASSERT( false);
                case TYMED_GDI   :
                {

                    TPicture *Picture = new TPicture();
                    Picture->Graphic = new Graphics::TBitmap();
                    Picture->Bitmap->Handle = m_Medium.hBitmap;

                    DrawImage( canvas, Rc, EmptyStr, Picture, m_bResize? Et_Etire : Et_Normal);
                    Picture->Bitmap->ReleaseHandle();
                    delete Picture;
                }break;
                default :
                {
                    IViewObject *pViewObj = m_pViewObj?m_pViewObj:m_pViewObj2;
                    ChkOLE( TAGL, pViewObj->Draw( m_FormatEtc.dwAspect, m_FormatEtc.lindex, &dvFlag, m_FormatEtc.ptd, NULL,
                                                canvas->Handle, &rcBound1, NULL, NULL, 0));
                }
            }
            ::_SelectClipRgn( TAGL, canvas->Handle, NULL);

      }CATCH_EXCEPTION(TAGL);
    }
    NumPage = -1;
}
TCoordonnee __fastcall COle::GetHauteur( const TCoorPoint &TailleFeuille, bool bOnEstEnHautDeLaPage, long NumPage)
{
//    short nbFeuillesEnHauteur = ceil( m_Size.y.Twips / TailleFeuille.y.Twips);
//    short nbFeuillesEnLargeur = ceil( m_Size.x.Twips / TailleFeuille.x.Twips);
//    return (TailleFeuille.y.Twips * (nbFeuillesEnHauteur * nbFeuillesEnLargeur - (NumPage+1)));
    if( !bOnEstEnHautDeLaPage && (m_Size.y.Twips > TailleFeuille.y.Twips) && (NumPage == -1))
    {
        TRACEF(  TAGL, "COle::GetHauteur m_Size.y.Twips[%.2lf] ", m_Size.y.Twips);
        return m_Size.y.Twips;
    }
    TRACEF(  TAGL, "COle::Draw min( m_Size.y.Twips[%.2lf], TailleFeuille.y.Twips[%.2lf])[%.2lf]", m_Size.y.Twips, TailleFeuille.y.Twips, min( m_Size.y.Twips, TailleFeuille.y.Twips));
    return min( m_Size.y.Twips, TailleFeuille.y.Twips);
}
AnsiString  __fastcall COle::GetAppName()
{
    AnsiString sAppName;
    CLSID clsid;
    LPOLESTR Buffer;
    Buffer = new OLECHAR[m_File.Length()+1];
    memset( Buffer, 0, (m_File.Length()+1)*sizeof( Buffer[0]));
    ChkOLE( TAGL, ::GetClassFile(m_File.WideChar(Buffer, m_File.Length()), &clsid));
    delete[] Buffer;
    ChkOLE( TAGL, ::ProgIDFromCLSID(clsid, &Buffer));
    sAppName = AnsiString( Buffer);
    ::CoTaskMemFree( Buffer);
    return sAppName;
}

#if 0
// returns a DEVMODE and DEVNAMES for the printer name specified
BOOL GetPrinterDevice(LPTSTR pszPrinterName, HGLOBAL* phDevNames, HGLOBAL* phDevMode)
{
    // if NULL is passed, then assume we are setting app object's
    // devmode and devnames
    if (phDevMode == NULL || phDevNames == NULL)
        return FALSE;

    // Open printer
    HANDLE hPrinter;
    if (OpenPrinter(pszPrinterName, &hPrinter, NULL) == FALSE)
        return FALSE;

    // obtain PRINTER_INFO_2 structure and close printer
    DWORD dwBytesReturned, dwBytesNeeded;
    GetPrinter(hPrinter, 2, NULL, 0, &dwBytesNeeded);
    PRINTER_INFO_2* p2 = (PRINTER_INFO_2*)GlobalAlloc(GPTR,
        dwBytesNeeded);
    if (GetPrinter(hPrinter, 2, (LPBYTE)p2, dwBytesNeeded,
       &dwBytesReturned) == 0) {
       GlobalFree(p2);
       ClosePrinter(hPrinter);
       return FALSE;
    }
    ClosePrinter(hPrinter);

    // Allocate a global handle for DEVMODE
    HGLOBAL  hDevMode = GlobalAlloc(GHND, sizeof(*p2->pDevMode) +
       p2->pDevMode->dmDriverExtra);
    ASSERT(hDevMode);
    DEVMODE* pDevMode = (DEVMODE*)GlobalLock(hDevMode);
    ASSERT(pDevMode);

    // copy DEVMODE data from PRINTER_INFO_2::pDevMode
    memcpy(pDevMode, p2->pDevMode, sizeof(*p2->pDevMode) +
       p2->pDevMode->dmDriverExtra);
    GlobalUnlock(hDevMode);

    // Compute size of DEVNAMES structure from PRINTER_INFO_2's data
    DWORD drvNameLen = lstrlen(p2->pDriverName)+1;  // driver name
    DWORD ptrNameLen = lstrlen(p2->pPrinterName)+1; // printer name
    DWORD porNameLen = lstrlen(p2->pPortName)+1;    // port name

    // Allocate a global handle big enough to hold DEVNAMES.
    HGLOBAL hDevNames = GlobalAlloc(GHND,
        sizeof(DEVNAMES) +
        (drvNameLen + ptrNameLen + porNameLen)*sizeof(TCHAR));
    ASSERT(hDevNames);
    DEVNAMES* pDevNames = (DEVNAMES*)GlobalLock(hDevNames);
    ASSERT(pDevNames);

    // Copy the DEVNAMES information from PRINTER_INFO_2
    // tcOffset = TCHAR Offset into structure
    int tcOffset = sizeof(DEVNAMES)/sizeof(TCHAR);
    ASSERT(sizeof(DEVNAMES) == tcOffset*sizeof(TCHAR));

    pDevNames->wDriverOffset = tcOffset;
    memcpy((LPTSTR)pDevNames + tcOffset, p2->pDriverName,
        drvNameLen*sizeof(TCHAR));
    tcOffset += drvNameLen;

    pDevNames->wDeviceOffset = tcOffset;
    memcpy((LPTSTR)pDevNames + tcOffset, p2->pPrinterName,
        ptrNameLen*sizeof(TCHAR));
    tcOffset += ptrNameLen;

    pDevNames->wOutputOffset = tcOffset;
    memcpy((LPTSTR)pDevNames + tcOffset, p2->pPortName,
        porNameLen*sizeof(TCHAR));
    pDevNames->wDefault = 0;

    GlobalUnlock(hDevNames);
    GlobalFree(p2);   // free PRINTER_INFO_2

    // set the new hDevMode and hDevNames
    *phDevMode = hDevMode;
    *phDevNames = hDevNames;
    return TRUE;
}
#define UT_DVTARGETDEVICE_SIZE  (sizeof(DWORD) + sizeof(WORD) * 4)
DVTARGETDEVICE* ptdCreateTargetDevice(HGLOBAL hDevNames, HGLOBAL hDevMode, LPSTR lpszFileName,	UINT nCopies)
{
    DVTARGETDEVICE* ptd = NULL;
    LPDEVNAMES      pDN;
    LPDEVMODE       pDM;
    LPSTR           pszName, pszOutputName;
    DWORD           dwDriverNameSize, dwDeviceNameSize, dwOutputNameSize;
    DWORD           dwDevNamesSize, dwDevModeSize, dwPtdSize;

    int cbOffset, cchWritten;

    pDN = (LPDEVNAMES)GlobalLock(hDevNames);
    if (pDN == NULL ) return NULL;

    pDM = (LPDEVMODE)GlobalLock(hDevMode);
    if (pDM == NULL) goto errReturn;

    dwDevNamesSize = sizeof(DEVNAMES);

    pszName = (LPSTR)pDN + pDN->wDriverOffset;
    dwDriverNameSize = (lstrlen(pszName) + 1/* NULL term */);
    dwDevNamesSize += (dwDevNamesSize * sizeof(WCHAR) /*double wide*/);

    pszName = (LPSTR)pDN + pDN->wDeviceOffset;
    dwDeviceNameSize = (lstrlen(pszName) + 1/* NULL term */);
    dwDevNamesSize += (dwDeviceNameSize * sizeof(WCHAR) /*double wide*/);

    if (lpszFileName && lpszFileName[0])
	    pszName = lpszFileName;
    else
	    pszName = (LPSTR)pDN + pDN->wOutputOffset;

    pszOutputName = pszName;
    dwOutputNameSize = (lstrlen(pszName) + 1/* NULL term */);
    dwDevNamesSize += (dwOutputNameSize * sizeof(WCHAR) /*double wide*/);

    dwDevModeSize = (DWORD)sizeof(DEVMODEW) +
                    ((pDM->dmSize > sizeof(DEVMODEA)) ? (pDM->dmSize - sizeof(DEVMODEA)) : 0) +
                      pDM->dmDriverExtra;

    dwPtdSize = sizeof(DWORD) + dwDevNamesSize + dwDevModeSize;

    ptd = (DVTARGETDEVICE*)CoTaskMemAlloc(dwPtdSize + 1000);

    if (ptd != NULL) {

	    cbOffset = UT_DVTARGETDEVICE_SIZE;

     // Zero everything first....
        ZeroMemory(ptd, dwPtdSize);
		ptd->tdSize = (UINT)dwPtdSize;

     // Add driver name and convert to unicode...
		ptd->tdDriverNameOffset = (USHORT)cbOffset;
    	cchWritten = MultiByteToWideChar(CP_ACP, 0,
             (LPSTR)((BYTE*)pDN + pDN->wDriverOffset), dwDriverNameSize,
             (LPWSTR)((BYTE*)ptd + ptd->tdDriverNameOffset), dwDriverNameSize);

		cbOffset += cchWritten * sizeof(WCHAR);

     // Add device name and convert to unicode...
		ptd->tdDeviceNameOffset = (USHORT)cbOffset;
    	cchWritten = MultiByteToWideChar(CP_ACP, 0,
             (LPSTR)((BYTE*)pDN + pDN->wDeviceOffset), dwDeviceNameSize,
             (LPWSTR)((BYTE*)ptd + ptd->tdDeviceNameOffset), dwDeviceNameSize);

		cbOffset += cchWritten * sizeof(WCHAR);

     // Add port name and convert to unicode...
		ptd->tdPortNameOffset = (USHORT)cbOffset;
    	cchWritten = MultiByteToWideChar(CP_ACP, 0,
             (LPSTR)pszOutputName, dwOutputNameSize,
             (LPWSTR)((BYTE*)ptd + ptd->tdPortNameOffset), dwOutputNameSize);

		cbOffset += cchWritten * sizeof(WCHAR);

		ptd->tdExtDevmodeOffset = (USHORT)cbOffset;

		{
		    LPDEVMODEW  ptdDM;
		    ptdDM = (LPDEVMODEW)((LPSTR)ptd + ptd->tdExtDevmodeOffset);

		//  First, translate the dmDeviceName
		    MultiByteToWideChar(CP_ACP, 0,
                    (LPSTR)pDM->dmDeviceName, CCHDEVICENAME,
			        ptdDM->dmDeviceName, CCHDEVICENAME);

		//  Now check to see if we have a dmFormName to translate
		    if (pDM->dmSize <= FIELD_OFFSET(DEVMODEA, dmFormName)) {

			    //  No dmFormName, just copy the remaining m bytes
			    CopyMemory(&ptdDM->dmSpecVersion, &pDM->dmSpecVersion,
				       pDM->dmSize - CCHDEVICENAME);
		    }
		    else {

			    //  There is a dmFormName;  copy the bytes between the names first
			    CopyMemory(&ptdDM->dmSpecVersion, &pDM->dmSpecVersion,
				       FIELD_OFFSET(DEVMODEA, dmFormName) -
					   FIELD_OFFSET(DEVMODEA, dmSpecVersion));

			    //  Now translate the dmFormName
			    MultiByteToWideChar(CP_ACP, 0,
                    (LPSTR)pDM->dmFormName, CCHFORMNAME,
					ptdDM->dmFormName, CCHFORMNAME);

			    //  Now copy the remaining m bytes
			    if (pDM->dmSize > FIELD_OFFSET(DEVMODEA, dmLogPixels))
				    CopyMemory(&ptdDM->dmLogPixels, &pDM->dmLogPixels,
					       pDM->dmSize - FIELD_OFFSET(DEVMODEA, dmLogPixels));

		    }

        ptdDM->dmSize = sizeof(DEVMODEW);
		if (pDM->dmSize > sizeof(DEVMODEA)) {
			ptdDM->dmSize = (WORD)(ptdDM->dmSize + (WORD)(pDM->dmSize - sizeof(DEVMODEA)));
		}

		ptdDM->dmFields |= DM_COLLATE;
		ptdDM->dmFields |= DM_COPIES;
		ptdDM->dmCollate = (SHORT)DMCOLLATE_FALSE;
		ptdDM->dmCopies = (SHORT)nCopies;

		//  Copy the extra driver bytes
		CopyMemory(((BYTE*)ptdDM) + ptdDM->dmSize, ((BYTE*)pDM) + pDM->dmSize,
			   pDM->dmDriverExtra);

		}
	}

	GlobalUnlock(hDevMode);

errReturn:
	GlobalUnlock(hDevNames);
	return ptd;
}
DVTARGETDEVICE* __fastcall COle::InitTargetDevice()
{    HDC h;
    if( !ms_ptd)
    {
        DWORD dwDevNamesSize, dwDevModeSize, dwPtdSize;
        HGLOBAL hDevNames, hDevMode;
        char* s = "hp deskjet 920c series";//Printer()->Printers->Strings[Printer()->PrinterIndex].c_str();
GetPrinterDevice( s, &hDevNames, &hDevMode);
ms_ptd  = ptdCreateTargetDevice(hDevNames, hDevMode, s,	1);
return ms_ptd;
        LPOLESTR lpszDriverNameOle = L"DISPLAY";
        LPOLESTR lpszDeviceNameOle = L"";
        LPOLESTR lpszPortNameOle   = L"";

        int nDriverNameSize = (lpszDriverNameOle == NULL) ? 0 : (wcslen(lpszDriverNameOle)+1)*sizeof(OLECHAR);
        int nDeviceNameSize = (lpszDeviceNameOle == NULL) ? 0 : (wcslen(lpszDeviceNameOle)+1)*sizeof(OLECHAR);
        int nPortNameSize   = (lpszPortNameOle == NULL)   ? 0 : (wcslen(lpszPortNameOle)  +1)*sizeof(OLECHAR);

        DEVMODEW DevModeOle;
        if( !EnumDisplaySettingsW( NULL, ENUM_CURRENT_SETTINGS, &DevModeOle))
            AfficheLastErrorT("EnumDisplaySettingsW");
        DevModeOle.dmFields |= DM_ORIENTATION | DM_PAPERSIZE | DM_COPIES;
        DevModeOle.dmOrientation = DMORIENT_PORTRAIT;
        DevModeOle.dmCopies      = 1;
        DevModeOle.dmPaperSize   = DMPAPER_A4;

        dwDevNamesSize = nDriverNameSize + nDeviceNameSize + nPortNameSize;
        dwDevModeSize = (DWORD)(DevModeOle.dmSize + DevModeOle.dmDriverExtra);

        dwPtdSize = sizeof(DVTARGETDEVICE) + dwDevNamesSize + dwDevModeSize;

        if ((ms_ptd = (DVTARGETDEVICE*)CoTaskMemAlloc(dwPtdSize)) != NULL)
        {
            // copy in the info
            ms_ptd->tdSize = (UINT)dwPtdSize;

            ms_ptd->tdDriverNameOffset = sizeof(DVTARGETDEVICE);
                wcscpy((LPOLESTR)((BYTE*)ms_ptd + ms_ptd->tdDriverNameOffset), lpszDriverNameOle);
            ms_ptd->tdDeviceNameOffset = (WORD)(ms_ptd->tdDriverNameOffset + nDriverNameSize);
                wcscpy((LPOLESTR)((BYTE*)ms_ptd + ms_ptd->tdDeviceNameOffset), lpszDeviceNameOle);
            ms_ptd->tdPortNameOffset = (WORD)(ms_ptd->tdDeviceNameOffset + nDeviceNameSize);
                wcscpy((LPOLESTR)((BYTE*)ms_ptd + ms_ptd->tdPortNameOffset),   lpszPortNameOle);
            ms_ptd->tdExtDevmodeOffset = (WORD)(ms_ptd->tdPortNameOffset + nPortNameSize);
                memcpy(           (BYTE*)ms_ptd + ms_ptd->tdExtDevmodeOffset,   &DevModeOle,
                       DevModeOle.dmSize+DevModeOle.dmDriverExtra);
        }
    }
	return ms_ptd;
}
#endif

#if 0
class My_TComponent: public TCustomForm
{
    public :
        virtual HRESULT __stdcall QueryInterface(const GUID &IID, void *Obj);//{return QueryInterface( IID, Obj);};
       // __fastcall virtual My_TComponent( TComponent *AOwner):TComponent(AOwner){};
};
void CopieOleToMetaFile( CRichEditOleCallback *rec, TObject *Support, RECT rOutput)
{
    TCanvas *canvas = (TCanvas*)Support;
    LPOLESTR Buffer = NULL;
    AnsiString NomFichier = "c:\\temp\\Tests CD 5.9doc.doc"/*"c:\\temp\\analyse1.xls"*/, Fonc, aFichierASupprimer;
	IOleObject *pOleObject = NULL;
    IOleDocumentView *pOleDocView = NULL;
    IStorage* pStg = NULL;
	IDataObject *pDataObject = NULL;
    IViewObject2 *pViewObj = NULL;
    IOleClientSite *pClientSite=NULL;
    HRESULT hr;         //tolegraphic
    SIZE Size={0,0};
    FORMATETC FormatEtc,FormatEtcOk; memset( &FormatEtc, 0, sizeof( FormatEtc));
    STGMEDIUM medium;                memset( &medium, 0, sizeof( medium));
    IPrint *pPrintObj = NULL;
    STATSTG Fichier;
/* TForm  *f = new TForm( (TComponent*)NULL);
 f->Visible = true;
 f->Width = 500;
 f->Height = 500;
 TTreeView *tv = new TTreeView(f);
 tv->Parent = f;
 tv->Align = alClient;*/
    try{try{
        if( !IsValidCanvas( Support)) return;
        FormatEtc.cfFormat = 0;
        FormatEtc.ptd      =CreateTargetDevice();
        FormatEtc.dwAspect = DVASPECT_DOCPRINT;
        FormatEtc.lindex   = -1;
        FormatEtc.tymed    = TYMED_NULL ;

        Fonc = "OleInitialize";         hr = OleInitialize(NULL);
        SetLastError( hr); if( FAILED( hr)) throw ELastError(0, Fonc);
        Fonc = "StgCreateDocfile";      hr = StgCreateDocfile( NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE
                                                                 | STGM_DIRECT | STGM_CREATE, 0, &pStg);
        SetLastError( hr); if( FAILED( hr)) throw ELastError(1, Fonc);

        // récupération du nom du fichier généré pour pouvoir le supprimer après;
        m_pStg->Stat(&Fichier, STATFLAG_DEFAULT);
        aFichierASupprimer = AnsiString(WideString(Fichier.pwcsName));

//       CRichEditOleCallback     GetControllingUnknown()
//         My_TComponent *c = new My_TComponent( f);
/*TOleContainer	*s = new  TOleContainer	(f);
s->Parent = f;
s->AllowActiveDoc = true;
s->Visible =false;
s->AllowInPlace = true;
//s->AutoVerbMenu= true;

s->CreateObjectFromFile( NomFichier, false);
s->Run();
pOleObject = s->OleObjectInterface;*/
/*        Fonc = "QueryInterface";     hr =  GetControllingUnknown()->QueryInterface( IID_IOleClientSite, (void**)&pClientSite);
        SetLastError( hr); if( FAILED( hr)) throw ELastError(2, Fonc);
  */
        Buffer = new OLECHAR[NomFichier.Length()+1]; memset( Buffer, 0, (NomFichier.Length()+1)*sizeof( Buffer[0]));
        Fonc = "OleCreateFromFile";     hr = OleCreateFromFile( CLSID_NULL, NomFichier.WideChar(Buffer, NomFichier.Length()), IID_IOleObject,
                                                                OLERENDER_DRAW, NULL, pClientSite, pStg, (void **)&pOleObject);
        SetLastError( hr); if( FAILED( hr)) throw ELastError(2, Fonc);


    //    pOleObject->DoVerb(OLEIVERB_OPEN, 0, NULL, 0, 0, &rOutput);

        IRunnableObject *pRunObject = NULL;
        Fonc = "QueryInterface IID_IRunnableObject";      hr = pOleObject->QueryInterface(IID_IRunnableObject, (void**)&pRunObject);
        SetLastError( hr); if( FAILED( hr)) throw ELastError(2, Fonc);
        Fonc = "Run"; hr = pRunObject->Run( NULL);
        SetLastError( hr); if( FAILED( hr)) throw ELastError(2, Fonc);

        Fonc = "QueryInterface";        hr = pOleObject->QueryInterface(IID_IViewObject2, (void**)&pViewObj );
        SetLastError( hr); if( FAILED( hr)) throw ELastError(3, Fonc);

        IOleDocumentView *pDocView = NULL;
        Fonc = "QueryInterface IID_IOleDocumentView";      hr = pOleObject->QueryInterface(IID_IOleDocumentView, (void**)&pDocView);
        SetLastError( hr); if( FAILED( hr)) throw ELastError(2, Fonc);

//    InsereInterfaces( tv->Items, NULL,pOleObject);
        Fonc = "QueryInterface";        hr = pDocView->QueryInterface(IID_IPrint, (void**)&pPrintObj );
        SetLastError( hr); if( FAILED( hr)) throw ELastError(3, Fonc);
        LONG FirstPage, NbPages;

        PAGESET *pgset = new PAGESET;;
        pgset->cbStruct = sizeof(pgset);
        pgset->fOddPages = 0;
        pgset->fEvenPages = 0;
        pgset->cPageRange = 1;
        pgset->rgPages[0].nFromPage = 0;
        pgset->rgPages[0].nToPage = PAGESET_TOLASTPAGE;
/*        Fonc = "Print";                 hr = pPrintObj->Print( PRINTFLAG_FORCEPROPERTIES, &FormatEtc.ptd,
                                                               &pgset, NULL,  NULL, 5, &FirstPage, &NbPages);
        SetLastError( hr); if( FAILED( hr)) throw ELastError(3, Fonc);

                        */
        FormatEtc.dwAspect = DVASPECT_DOCPRINT;

        Fonc = "GetExtent";        hr = pViewObj->GetExtent( FormatEtc.dwAspect, -1, FormatEtc.ptd, &Size);
        SetLastError( hr); if( FAILED( hr)) throw ELastError(3, Fonc);
        FormatEtc.dwAspect = DVASPECT_DOCPRINT;

        RECTL rcBound={rOutput.left,rOutput.top,rOutput.left+Size.cx/MM_PER_INCH, rOutput.top+Size.cy/MM_PER_INCH};
        DVASPECTINFO dvFlag = {sizeof( dvFlag), DVASPECTINFOFLAG_CANOPTIMIZE};
        Fonc = "Draw";        hr = pViewObj->Draw( FormatEtc.dwAspect , -1, &dvFlag, FormatEtc.ptd, NULL, canvas->Handle, &rcBound, NULL, ContinueDrawing, 1);
        SetLastError( hr); if( FAILED( hr)) throw ELastError(3, Fonc);

/*        IOleCache *pDataObject = NULL;
        FormatEtc.dwAspect = DVASPECT_DOCPRINT;
        Fonc = "QueryInterface";        hr = pOleObject->QueryInterface(IID_IOleCache, (void**)&pDataObject );
        SetLastError( hr); if( FAILED( hr)) throw ELastError(3, Fonc);
         DWORD d;
        Fonc = "Cache";        hr = pDataObject->Cache( &FormatEtc, ADVF_ONLYONCE,&d);
        SetLastError( hr); if( FAILED( hr)) throw ELastError(3, Fonc);*/

/*        Fonc = "GetExtent";        hr = p->GetExtent( FormatEtc.dwAspect, -1, FormatEtc.ptd, &Size);
        SetLastError( hr); if( FAILED( hr)) throw ELastError(3, Fonc);*/

/*        Fonc = "QueryInterface";        hr = pOleObject->QueryInterface(IID_IOleDocumentView, (void**)&pOleDocView );
        SetLastError( hr); if( FAILED( hr)) throw ELastError(3, Fonc);
        IOleInPlaceSite *ff=NULL;
        Fonc = "QueryInterface";        hr = pOleObject->QueryInterface(IID_IOleInPlaceSite, (void**)&ff );
        SetLastError( hr); if( FAILED( hr)) throw ELastError(3, Fonc);*/



        Size = Size;
    }catch(ELastError& e)
    {
     EICDisplayException( 1, e);
    }
    }__finally{
              ReleaseStgMedium( &medium);
        if( pPrintObj)      pPrintObj->Release();
        if( pOleDocView)    pOleDocView->Release();
        if( FormatEtc.ptd)  CoTaskMemFree(FormatEtc.ptd);
	    if (pOleObject)     pOleObject->Release();
        if( pStg)           pStg->Release();
        if( Buffer)         delete[] Buffer;
        OleUninitialize();
        if (FileExists(aFichierASupprimer)) DeleteFile(aFichierASupprimer);
    }
}
#endif
